#include "Mesh.h"

namespace Pulse
{
	SubMesh::SubMesh( void )
	{
		indicesOffset = 0;
		numTriangles = 0;
	}

	Mesh::Mesh( void )
	{
		m_pVertices = PSX_NULL;
		m_numVertices = 0;
		m_pIndices = PSX_NULL;
		m_numIndices = 0;
		m_pSubMeshes = PSX_NULL;
		m_numSubMeshes = 0;
	}

	Mesh::~Mesh( void )
	{
		m_numSubMeshes = 0;
		PSX_SafeDeleteArray( m_pSubMeshes );
		m_numVertices = 0;
		PSX_SafeDeleteArray( m_pVertices );
	}

	void Mesh::ResizeSubMeshes( SIZE_T32 newSize )
	{
		if ( GetNumSubMeshes() == newSize )
			return;

		if ( newSize == 0 )
		{
			PSX_SafeDeleteArray( m_pSubMeshes );
			m_numSubMeshes = 0;
			return;
		}

		SubMesh *pNewSubMeshes = new SubMesh[newSize];
		SIZE_T32 numToCopy = GetNumSubMeshes() < newSize ? GetNumSubMeshes() : newSize;

		if ( numToCopy )
		{		// Zero out new array
			PSX_ZeroMem( pNewSubMeshes, sizeof(SubMesh) * newSize );
			PSX_MemCopyPerByte( pNewSubMeshes, m_pSubMeshes, sizeof(SubMesh) * numToCopy );
		}

		delete [] m_pSubMeshes;
		m_pSubMeshes = pNewSubMeshes;
		m_numSubMeshes = newSize;

	}

	void Mesh::ResizeVertices( SIZE_T32 newSize )
	{
		if ( GetNumVertices() == newSize )
			return;

		if ( newSize == 0 )
		{
			PSX_SafeDeleteArray(m_pVertices);
			m_numVertices = 0;
			UpdateElements();
			return;
		}

		Vector3 *pNewVertices = new Vector3[newSize];
		SIZE_T32 numToCopy = GetNumVertices() < newSize ? GetNumVertices() : newSize;

		if ( numToCopy )
			PSX_MemCopyPerByte( pNewVertices, m_pVertices, sizeof(Vector3) * numToCopy );

		delete [] m_pVertices;
		m_pVertices = pNewVertices;
		m_numVertices = newSize;

		UpdateElements();

	}

	void Mesh::ResizeIndices( SIZE_T32 newSize )
	{
		if ( GetNumIndices() == newSize )
			return;

		if ( newSize == 0 )
		{
			PSX_SafeDeleteArray( m_pIndices );
			m_numIndices = 0;
			return;
		}

		UPOS_T32 *pNewIndices = new UPOS_T32[newSize];
		const SIZE_T32 numToCopy = GetNumIndices() < newSize ? GetNumIndices() : newSize;

		if ( numToCopy )
			PSX_MemCopyPerByte( pNewIndices, m_pIndices, sizeof(UPOS_T32) * numToCopy );

		delete [] m_pIndices;
		m_pIndices = pNewIndices;
		m_numIndices = newSize;
	}

	SubMesh * Mesh::GetSubMesh( UPOS_T32 index ) 
	{
		// We want to make sure we never get 
		//	out-of-bound by automatically resizing the 
		//	submesh list if needed.

		if ( index >= GetNumSubMeshes() )
			ResizeSubMeshes( index + 1 );

		return &m_pSubMeshes[index];
	}

	void Mesh::SetNormalsEnabled( BOOL bEnable )
	{
		if ( bEnable == m_bHaveNormals )
			return;

		m_bHaveNormals = bEnable;

		UpdateNormalElement();
	}

	void Mesh::UpdateElements( void )
	{
		UpdateNormalElement();
		UpdateUVElement();
	}

	void Mesh::ResizeUVSets( SIZE_T32 newSize )
	{
		if ( m_UVSets.GetSize() == newSize )
			return;

		m_UVSets.Resize( newSize );
	
		UpdateUVElement();
	}

	void Mesh::UpdateNormalElement( void )
	{
		if ( m_bHaveNormals == FALSE )
		{
			m_normals.Clear();
			return;
		}

		m_normals.Resize( m_numVertices );
	}

	void Mesh::UpdateUVElement( void )
	{
		for ( SIZE_T i = 0; i < m_UVSets.GetSize(); ++i )
			m_UVSets[i].UVs.Resize(m_numVertices);
	}

}